package com.dgut.edu.cn.design.mode.strategy;

import com.google.common.collect.Maps;
import org.apache.commons.collections4.MapUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.stereotype.Service;

import javax.annotation.PostConstruct;
import java.util.Map;
import java.util.Optional;

/**
 * @description:
 * @author: hongbin.zheng
 * @create: 2023-07-17 16:59
 **/
@Service
public class StrategyServiceManager {
	@Autowired
	private ApplicationContext context;
	/**
	 * 存储策略:类型：具体实现类
	 */
	private Map<StrategyType, Map<String, Object>> map;

	public <E> E getStrategyInstance(StrategyType strategyType, String type, Class<E> eClass) {
		Map<String, Object> strategyTypeMap = map.get(strategyType);
		if (strategyTypeMap != null && !map.isEmpty()) {
			Object bean = strategyTypeMap.get(type);
			if (bean != null) {
				return eClass.cast(bean);
			}
		}
		return null;
	}


	public <E> E getStrategyInstanceV2(StrategyType strategyType, String type, Class<E> eClass) {
		if (strategyType == null || StringUtils.isEmpty(type) || eClass == null) {
			return null;
		}
		return Optional.ofNullable(strategyType)
				.map(st -> map.get(st))
				.filter(MapUtils::isNotEmpty)
				.map(strategyTypeMap -> strategyTypeMap.get(type))
				.map(eClass::cast)
				.orElse(null);
	}


	@PostConstruct
	private void init() {
		map = Maps.newHashMap();

		Map<String, Object> beans = context.getBeansWithAnnotation(StrategyAnnotation.class);
		for (Object value : beans.values()) {
			StrategyAnnotation annotation = value.getClass().getAnnotation(StrategyAnnotation.class);
			StrategyType[] strategyTypes = annotation.strategyType();
			String[] dataTypes = annotation.dataType();
			if (strategyTypes == null || strategyTypes.length == 0 || dataTypes == null || dataTypes.length == 0) {
				throw new RuntimeException("注解上必填字段不能为空");
			}

			for (StrategyType strategyType : strategyTypes) {
				for (String dataType : dataTypes) {
					map.computeIfAbsent(strategyType, k -> Maps.newHashMap()).put(dataType, value);
				}
			}
		}
	}

}
